"""DHCP地址池管理."""

import ipaddress
import logging
from typing import List, Optional, Dict, Tuple

from sqlalchemy import select, and_, or_, func
from sqlalchemy.ext.asyncio import AsyncSession

from netsphere.models.dhcp import DHCPScope, DHCPReservation, DHCPLease
from netsphere.services.ipam import IPAllocator

logger = logging.getLogger(__name__)


class DHCPPoolManager:
    """DHCP地址池管理器."""
    
    def __init__(self, session: AsyncSession):
        """初始化地址池管理器.
        
        Args:
            session: 数据库会话
        """
        self.session = session
        self.ip_allocator = IPAllocator(session)
    
    async def create_scope(
        self,
        name: str,
        network: str,
        subnet_mask: str,
        start_ip: str,
        end_ip: str,
        gateway: str = None,
        dns_servers: List[str] = None,
        domain_name: str = None,
        lease_time: int = 86400,
        description: str = None,
    ) -> DHCPScope:
        """创建DHCP作用域.
        
        Args:
            name: 作用域名称
            network: 网络地址
            subnet_mask: 子网掩码
            start_ip: 起始IP地址
            end_ip: 结束IP地址
            gateway: 默认网关
            dns_servers: DNS服务器列表
            domain_name: 域名
            lease_time: 租约时间(秒)
            description: 描述信息
            
        Returns:
            DHCPScope实例
        """
        # 验证IP地址范围
        start = ipaddress.IPv4Address(start_ip)
        end = ipaddress.IPv4Address(end_ip)
        
        if start >= end:
            raise ValueError("Start IP must be less than end IP")
        
        # 验证IP地址是否在网段内
        network_obj = ipaddress.IPv4Network(f"{network}/{subnet_mask}")
        if start not in network_obj or end not in network_obj:
            raise ValueError("IP range must be within the network")
        
        scope = DHCPScope(
            name=name,
            network=network,
            subnet_mask=subnet_mask,
            start_ip=start_ip,
            end_ip=end_ip,
            gateway=gateway,
            dns_servers=dns_servers or [],
            domain_name=domain_name,
            lease_time=lease_time,
            description=description,
        )
        
        self.session.add(scope)
        await self.session.commit()
        return scope
    
    async def get_scope(self, scope_id: int) -> Optional[DHCPScope]:
        """获取作用域详情.
        
        Args:
            scope_id: 作用域ID
            
        Returns:
            DHCPScope实例或None
        """
        return await self.session.get(DHCPScope, scope_id)
    
    async def list_scopes(
        self,
        is_active: bool = None,
    ) -> List[DHCPScope]:
        """列出作用域.
        
        Args:
            is_active: 过滤活跃状态
            
        Returns:
            作用域列表
        """
        query = select(DHCPScope)
        
        if is_active is not None:
            query = query.where(DHCPScope.is_active == is_active)
        
        result = await self.session.execute(query)
        return list(result.scalars().all())
    
    async def get_scope_stats(self, scope_id: int) -> Dict[str, int]:
        """获取作用域统计信息.
        
        Args:
            scope_id: 作用域ID
            
        Returns:
            统计信息字典
        """
        scope = await self.get_scope(scope_id)
        if not scope:
            raise ValueError("Scope not found")
        
        # 计算IP范围
        start = ipaddress.IPv4Address(scope.start_ip)
        end = ipaddress.IPv4Address(scope.end_ip)
        total_ips = int(end) - int(start) + 1
        
        # 查询已用IP
        used_query = select(func.count(DHCPLease.id)).where(
            and_(
                DHCPLease.scope_id == scope_id,
                DHCPLease.state == "active",
                DHCPLease.lease_end > func.now()
            )
        )
        result = await self.session.execute(used_query)
        used_ips = result.scalar()
        
        # 查询保留IP
        reserved_query = select(func.count(DHCPReservation.id)).where(
            and_(
                DHCPReservation.scope_id == scope_id,
                DHCPReservation.is_active == True
            )
        )
        result = await self.session.execute(reserved_query)
        reserved_ips = result.scalar()
        
        return {
            "total_ips": total_ips,
            "used_ips": used_ips,
            "reserved_ips": reserved_ips,
            "available_ips": total_ips - used_ips - reserved_ips,
        }
    
    async def create_reservation(
        self,
        scope_id: int,
        ip_address: str,
        mac_address: str,
        hostname: str = None,
        description: str = None,
    ) -> DHCPReservation:
        """创建保留地址.
        
        Args:
            scope_id: 作用域ID
            ip_address: 保留的IP地址
            mac_address: MAC地址
            hostname: 主机名
            description: 描述信息
            
        Returns:
            DHCPReservation实例
        """
        # 验证作用域存在
        scope = await self.get_scope(scope_id)
        if not scope:
            raise ValueError("Scope not found")
        
        # 验证IP地址在范围内
        ip = ipaddress.IPv4Address(ip_address)
        start = ipaddress.IPv4Address(scope.start_ip)
        end = ipaddress.IPv4Address(scope.end_ip)
        
        if ip < start or ip > end:
            raise ValueError("IP address not in scope range")
        
        # 检查IP是否已被保留
        existing = await self.session.execute(
            select(DHCPReservation).where(
                and_(
                    DHCPReservation.scope_id == scope_id,
                    DHCPReservation.ip_address == ip_address,
                    DHCPReservation.is_active == True
                )
            )
        )
        if existing.scalar_one_or_none():
            raise ValueError("IP address already reserved")
        
        # 检查MAC是否已被保留
        existing = await self.session.execute(
            select(DHCPReservation).where(
                and_(
                    DHCPReservation.scope_id == scope_id,
                    DHCPReservation.mac_address == mac_address,
                    DHCPReservation.is_active == True
                )
            )
        )
        if existing.scalar_one_or_none():
            raise ValueError("MAC address already has reservation")
        
        reservation = DHCPReservation(
            scope_id=scope_id,
            ip_address=ip_address,
            mac_address=mac_address.upper().replace("-", ":"),
            hostname=hostname,
            description=description,
        )
        
        self.session.add(reservation)
        await self.session.commit()
        return reservation
    
    async def get_reservation_by_mac(
        self,
        scope_id: int,
        mac_address: str,
    ) -> Optional[DHCPReservation]:
        """根据MAC地址获取保留地址.
        
        Args:
            scope_id: 作用域ID
            mac_address: MAC地址
            
        Returns:
            DHCPReservation实例或None
        """
        query = select(DHCPReservation).where(
            and_(
                DHCPReservation.scope_id == scope_id,
                DHCPReservation.mac_address == mac_address.upper().replace("-", ":"),
                DHCPReservation.is_active == True
            )
        )
        result = await self.session.execute(query)
        return result.scalar_one_or_none()
    
    async def list_reservations(
        self,
        scope_id: int = None,
        is_active: bool = None,
    ) -> List[DHCPReservation]:
        """列出保留地址.
        
        Args:
            scope_id: 作用域ID（可选）
            is_active: 过滤活跃状态
            
        Returns:
            保留地址列表
        """
        query = select(DHCPReservation)
        
        if scope_id is not None:
            query = query.where(DHCPReservation.scope_id == scope_id)
        if is_active is not None:
            query = query.where(DHCPReservation.is_active == is_active)
        
        result = await self.session.execute(query)
        return list(result.scalars().all())
    
    async def get_available_ip(
        self,
        scope_id: int,
        requested_ip: str = None,
    ) -> Optional[str]:
        """获取可用IP地址.
        
        Args:
            scope_id: 作用域ID
            requested_ip: 请求的IP地址
            
        Returns:
            可用IP地址或None
        """
        scope = await self.get_scope(scope_id)
        if not scope:
            raise ValueError("Scope not found")
        
        start = ipaddress.IPv4Address(scope.start_ip)
        end = ipaddress.IPv4Address(scope.end_ip)
        
        # 如果指定了请求的IP，检查是否可用
        if requested_ip:
            ip = ipaddress.IPv4Address(requested_ip)
            if ip < start or ip > end:
                return None
            
            # 检查是否已被使用或保留
            if await self._is_ip_available(scope_id, str(ip)):
                return str(ip)
            else:
                return None
        
        # 查找第一个可用IP
        for ip_int in range(int(start), int(end) + 1):
            ip_str = str(ipaddress.IPv4Address(ip_int))
            if await self._is_ip_available(scope_id, ip_str):
                return ip_str
        
        return None
    
    async def _is_ip_available(
        self,
        scope_id: int,
        ip_address: str,
    ) -> bool:
        """检查IP地址是否可用.
        
        Args:
            scope_id: 作用域ID
            ip_address: IP地址
            
        Returns:
            是否可用
        """
        # 检查是否已被保留
        reserved = await self.session.execute(
            select(DHCPReservation).where(
                and_(
                    DHCPReservation.scope_id == scope_id,
                    DHCPReservation.ip_address == ip_address,
                    DHCPReservation.is_active == True
                )
            )
        )
        if reserved.scalar_one_or_none():
            return False
        
        # 检查是否已被分配
        active_lease = await self.session.execute(
            select(DHCPLease).where(
                and_(
                    DHCPLease.scope_id == scope_id,
                    DHCPLease.ip_address == ip_address,
                    DHCPLease.state == "active",
                    DHCPLease.lease_end > func.now()
                )
            )
        )
        if active_lease.scalar_one_or_none():
            return False
        
        return True
    
    async def get_scope_utilization(
        self,
        scope_id: int,
    ) -> Dict[str, float]:
        """获取作用域使用率.
        
        Args:
            scope_id: 作用域ID
            
        Returns:
            使用率信息
        """
        stats = await self.get_scope_stats(scope_id)
        total = stats["total_ips"]
        used = stats["used_ips"] + stats["reserved_ips"]
        
        if total == 0:
            return {"utilization": 0.0}
        
        return {
            "utilization": (used / total) * 100,
            "used_percentage": (stats["used_ips"] / total) * 100,
            "reserved_percentage": (stats["reserved_ips"] / total) * 100,
            "available_percentage": (stats["available_ips"] / total) * 100,
        }